package health.carousel.tasks;

import health.carousel.connection.MailCommunicator;
import health.carousel.data.ErrorContainer;
import health.carousel.data.HtmlSafeString;
import health.carousel.data.PositionDetails;
import health.carousel.parsers.ContentParser;
import health.carousel.parsers.PositionDetailsParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.search.FlagTerm;
import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import static javax.mail.Flags.Flag.SEEN;

//@Service
@EnableScheduling
public class CheckMailTask {
    private static final Logger log = LoggerFactory.getLogger(CheckMailTask.class);

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    public static final String MAIL_AUTH_USER = "jobs@tailoredhealthcarestaffing.com";
    public static final String MAIL_AUTH_PASSWORD = "Orders23%";

    public static final String IMAP_SERVER = "outlook.office365.com";
    public static final String FOLDER_INBOX = "INBOX";

    public static final String PARALLON_COM = "@Parallon.com";
    public static final String MSNHEALTH_COM = "@msnhealth.com";

    private MailCommunicator communicator;
    private ContentParser contentParser;
    private PositionDetailsParser parallonPositionDetailsParser;
    private PositionDetailsParser msnPositionDetailsParser;
    private PositionDetailsParser defaultPositionDetailsParser;

    @Scheduled(fixedRate = 6000, initialDelay = 5000)
    public void checkNewMails() {
        log.info("Checking mail at: " + dateFormat.format(new Date()));
        ErrorContainer errorContainer = new ErrorContainer();
        checkInbox(errorContainer);

        if(errorContainer.getFailedMessages().size() > 0){
            log.info("####################");
            log.info(errorContainer.getFailedMessages().size() + " failed messages: ");
            for (String message : errorContainer.getFailedMessages()) {
                log.info("█" + message + "█");
            }
            log.info("####################");
            log.info("####################");
            log.info("####################");
        }
    }

    private void checkInbox(ErrorContainer errorContainer) {
        try {
            Properties props = System.getProperties();
            props.setProperty("mail.store.protocol", "imaps");

            Session session = Session.getDefaultInstance(props, null);
            Store store = session.getStore("imaps");
            store.connect(IMAP_SERVER, MAIL_AUTH_USER, MAIL_AUTH_PASSWORD);

            Folder inbox = store.getFolder(FOLDER_INBOX);
            try {
                inbox.open(Folder.READ_WRITE);
            } catch (MessagingException ex) {
                inbox.open(Folder.READ_ONLY);
            }

            FlagTerm searchCriteria = new FlagTerm(new Flags(SEEN), false);
            Message[] messages = inbox.search(searchCriteria);

            processMessages(messages, errorContainer);

            inbox.close(true);
            store.close();
        } catch (Exception e) {
            log.error("Got an exception when checking Inbox for new mails, exception details: " + e.getMessage(), e);
        }
    }

    private void processMessages(Message[] messages, ErrorContainer errorContainer) throws MessagingException, IOException, ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
        if (messages.length > 0) {
            log.info(messages.length + " new messages found.");
        }

        int numberOfMessages = messages.length;
        for (int i = 0; i < numberOfMessages; i++) {

            Address fromAddress = messages[i].getFrom()[0];
            String subject = messages[i].getSubject();
            Date sentDate = messages[i].getSentDate();
            Object originalContent = messages[i].getContent();

            log.info("Message " + (i + 1));
            log.info("From : " + fromAddress);
            log.info("Subject : " + subject);
            log.info("Sent Date : " + sentDate);
            log.info("Content : ");

            PositionDetailsParser positionDetailsParser = getParser(fromAddress);

            HtmlSafeString content = contentParser.parseMessageContent(originalContent);
            List<PositionDetails> detailsList = positionDetailsParser.parseContentDetails(content, errorContainer);


            communicator.putContentDataIntoDatabase(fromAddress, subject, sentDate, content.getText(), detailsList);

            if (i < numberOfMessages - 1) {

                log.info("");
                log.info("");
                log.info("================================================================================");
                log.info("================================================================================");
                log.info("                                  Next Mail");
                log.info("================================================================================");
                log.info("================================================================================");
                log.info("");
                log.info("");
            }
        }
    }

    private PositionDetailsParser getParser(Address fromAddress) {
        String emailAddress;
        if (fromAddress instanceof InternetAddress) {
            emailAddress = ((InternetAddress) fromAddress).getAddress();
        } else {
            emailAddress = fromAddress.toString();
        }

        if (emailAddress.endsWith(PARALLON_COM)) {
            return parallonPositionDetailsParser;
        } else if (emailAddress.endsWith(MSNHEALTH_COM)) {
            return msnPositionDetailsParser;
        } else {
            return defaultPositionDetailsParser;
        }
    }

    @Autowired
    public void setCommunicator(MailCommunicator communicator) {
        this.communicator = communicator;
    }

    @Autowired
    public void setContentParser(ContentParser contentParser) {
        this.contentParser = contentParser;
    }

    @Autowired
    public void setParallonPositionDetailsParser(PositionDetailsParser parallonPositionDetailsParser) {
        this.parallonPositionDetailsParser = parallonPositionDetailsParser;
    }

    @Autowired
    public void setMsnPositionDetailsParser(PositionDetailsParser msnPositionDetailsParser) {
        this.msnPositionDetailsParser = msnPositionDetailsParser;
    }

    @Autowired
    public void setDefaultPositionDetailsParser(PositionDetailsParser defaultPositionDetailsParser) {
        this.defaultPositionDetailsParser = defaultPositionDetailsParser;
    }
}
